package autotd.server;

import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


import autotd.gui.*;
import autotd.*;
import autotd.server.NetworkProtocol;

public class Server extends Thread implements NetworkProtocol {

	private ServerSocket server;
	private Socket socket;
	private BufferedReader in;
	private PrintWriter out;
	
	private TDSimulator sim;
	
	
	public Server(TDSimulator sim) {
		this.sim = sim;	
	}
	
	public void run() {
		try {
			server = new ServerSocket(DEFAULT_PORT_NUMBER);
			while(true){
				socket = server.accept();
				in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				out = new PrintWriter(socket.getOutputStream());
				
				//send connect command
				out.println(CONNECTED_RESPONSE);
				out.flush();
				String line = "";
				
				//listen for commands from client
				while(socket.isConnected()) {
					
					line = in.readLine();
					//System.out.println("Received: " + line);
					if(line != null) commandHandler(line);
					else break;
				}
			}
		} catch (IOException e) {
			GUI.log("Client Disconnected");
		}
		
	}
	
	private void commandHandler(String command) {
		String[] args = command.split(CMD_DELIM);
		
		if(args[0].equals(CMD_PLACE_TOWER)) {
			
			if(sim.placeTower(sim.getTowerType(args[3]), Integer.valueOf(args[1]), Integer.valueOf(args[2]))) {
				out.println(ACK);
				out.flush();
			} else {
				out.println(FAIL);
				out.flush();
			}
		
		} else if (args[0].equals(CMD_FIRE_TOWER)) {
			Point p = new Point(Integer.valueOf(args[1]), Integer.valueOf(args[2]));
			
			if(sim.shootMonster(p, sim.lookupMonster(Integer.valueOf(args[3])))) {
				out.println(ACK);
				out.flush();
			} else {
				out.println(FAIL);
				out.flush();
			}
		
		} else if(args[0].equals(CMD_QUERY_PLAYER)) {
			String send = CMD_QUERY_PLAYER + CMD_DELIM + sim.getPlayer().getMoney() + CMD_DELIM + sim.getPlayer().getLives();
			out.println(send);
			out.flush();
		
		} else if(args[0].equals(CMD_QUERY_MAP)) {
			
			String mapPoints = "";
			for(Point p: sim.getMap().getPath()) {
				mapPoints += p.x + CMD_DELIM + p.y + CMD_LIST_DELIM;
			}
			
			mapPoints = mapPoints.substring(0, mapPoints.lastIndexOf(CMD_LIST_DELIM));
			
			String send = CMD_QUERY_MAP + CMD_DELIM + sim.getMap().getWidth() + CMD_DELIM + sim.getMap().getLength() + CMD_DELIM + mapPoints;
			out.println(send);
			out.flush();
		
		} else if(args[0].equals(CMD_QUERY_MONSTERS)) {
			
			String monsters = "", specials = "";
			
			for(Monster m: sim.getActiveMonsters()) {
				
				//for(String s: m.specials)
					//specials += s;
				
				monsters += m.id + CMD_DELIM + m.pos.x + CMD_DELIM + m.pos.y + CMD_DELIM + m.Type.Name + CMD_DELIM + m.health + CMD_DELIM + m.Level + CMD_LIST_DELIM;
			}
			
			if(!sim.getActiveMonsters().isEmpty())
				monsters = monsters.substring(0, monsters.lastIndexOf(CMD_LIST_DELIM));
			
			String send = CMD_QUERY_MONSTERS + CMD_DELIM + monsters + CMD_DELIM;
			out.println(send);
			out.flush();
		
		} else if(args[0].equals(CMD_TICK)) {
			int ticks = 1;
			if(args.length != 1)
				ticks = Integer.valueOf(args[1]);
			
			for(int i = 0; i < ticks; ++i) {
				
				if(sim.tick()) {
					out.println(ACK);
					out.flush();
				} else {
					out.println(FAIL);
					out.flush();
				}
			}
				
		} else if(args[0].equals(CMD_QUERY_TOWERS)) {
			
			String queryTowers = "";
			for(Tower t: sim.getTowers()) {
				queryTowers += t.pos.x + CMD_DELIM + t.pos.y + CMD_DELIM + t.height + CMD_DELIM + t.Type.Name + CMD_LIST_DELIM; 
			}
			
			if(!sim.getTowers().isEmpty())
				queryTowers = queryTowers.substring(0, queryTowers.lastIndexOf(CMD_LIST_DELIM));
			
			String send = CMD_QUERY_TOWERS + CMD_DELIM + queryTowers;
			out.println(send);
			out.flush();
		
		} else if(args[0].equals(CMD_QUERY_TOWER_TYPES)) {
			
			String queryTowers = "";
			for(TowerType t: sim.getTowerTypes()) {
				queryTowers += t.toString() + CMD_LIST_DELIM; 
			}
			
			if(!sim.getTowers().isEmpty())
				queryTowers = queryTowers.substring(0, queryTowers.lastIndexOf(CMD_LIST_DELIM));
			
			String send = CMD_QUERY_TOWER_TYPES + CMD_DELIM + queryTowers;
			out.println(send);
			out.flush();
		}
	}
}
